var Chess = {
  ready: false,
  canvas: null,
  context: null,
  game: null,
  players: {},
  currentPlayer: null,
  mapPositionXRatio: 1,
  mapPositionYRatio: 1,

  init: function() {
    this.canvas = document.getElementById('canvas');
    this.context = this.canvas.getContext('2d');
    window.addEventListener('resize', UI.handleWindowResize, false);
    Socket.connectServer();
    Socket.registerEvent();
    Socket.registerView();
    var qrCodeImage = document.getElementById('qrCode');
    var url = 'http://' + location.host + '/client.html';
    UI.setClientUrl(url);
    UI.generateQrCodeForUrl(url, qrCodeImage);
    this.loadResources();
  },

  resetGame: function() {
    UI.showWaitingZone();
    UI.hideGameZone();
    UI.resetWaitingZone();
    GameAudio.playBackgroundAudio('waiting');
  },

  getPlayer: function(name) {
    return this.players[name];
  },
  
  loadResources: function() {
    var that = this;
    var resources = [
      {
        id: 'mapData',
        json: './map/map.json'
      },
      {
        id: 'mapImage',
        image: './map/map3.png'
      },
      {
        id: 'player',
        image: 'images/player-icon.png'
      }
    ];

    Resource.load(resources, function() {
      $.log('All resources loaded.');

      UI.setCanvasSize();
      that.preProcessMapData();
      that.resetGame();
      that.initGame();
//      UI.showGameZone();
//      UI.hideWaitingZone();
//      Chess.addPlayer('A')
//      Chess.currentPlayer = Chess.players['A'];
    });
  },

  preProcessMapData: function() {
    var mapData = Resource.get('mapData');
    var points = mapData.points;
    var xRatio = this.mapPositionXRatio = this.canvas.width / mapData.width;
    var yRatio = this.mapPositionYRatio = this.canvas.height / mapData.height;
    var spriteConfig = Config.sprite;
    var spriteRatio = spriteConfig.ratio = Math.min(xRatio, yRatio);

    var newPoints = this.points = [];
    points.forEach(function(point) {
      var newPoint = [
        point[0] * xRatio - (spriteConfig.width * spriteRatio) / 2,
        point[1] * yRatio - (spriteConfig.height * spriteRatio) / 2,
        point[2]
      ];
      newPoints.push(newPoint);
    });
  },

  initGame: function() {
    var game = this.game = new Game({
      FPS: 30,
      sprites: [],
      canvas: this.canvas,
      context: this.context
    });
    
    game.init();
    game.start();
  },

  startGame: function(startBy) {
    UI.showGameZone();
    UI.hideWaitingZone();

    var message = Message.get('gameStart') + ' ' +
      Message.get('startThrowBy', startBy);

    Message.showMainInfo(message, null, true);
    Socket.requestThrowDice(startBy);
    GameAudio.playBackgroundAudio('gaming');
  },

  throwDice: function(player, result) {
    UI.showStaticMap();
    Message.hideMainInfo();
    Dice.throwDice(result, function() {
      UI.hideStaticMap();
      UI.showCanvas();
      player.setPath(player.currentPointIndex,
        player.currentPointIndex + result, Chess.executeNext);
    });
  },

  /**
   * Create a player.
   * @param {String} name Player name, A or B
   * @param {HTMLImageElement} playerImage
   * @param {Number} positionOffset Player icon position offset value.
   */
  createPlayer: function(name, playerImage, positionOffset) {
    var startPoint = this.points[0];
    var spriteConfig = Config.sprite;
    var baseSpeed = spriteConfig.baseSpeed;
    var spriteWidth = spriteConfig.width;
    var spriteHeight = spriteConfig.height;
    var duration = spriteConfig.duration;
    var playerImageStartY = name == 'B' ? spriteHeight : 0;

    var spriteProperty = {
      name: name,
      x: startPoint[0],
      y: startPoint[1],
      positionOffset: positionOffset,
      baseSpeed: baseSpeed,
      defaultAnimationId: 'static',
      
      animations: {
        'static': new Animation({
          img: playerImage,
          frames: [
            {
              sx: 0, sy: playerImageStartY,
              sw: spriteWidth, sh: spriteHeight,
              duration: duration
            }
          ]
        }),

        'glint': new Animation({
          img: playerImage,
          frames: [
            {
              sx: 0, sy: playerImageStartY,
              sw: spriteWidth, sh: spriteHeight,
              duration: duration
            },
            {
              sx: spriteWidth, sy: playerImageStartY,
              sw: spriteWidth, sh: spriteHeight,
              duration: duration
            }
          ]
        })
      }
    };
    var player = new Sprite(spriteProperty);
    player.setSize();
    return player;
  },

  addPlayer: function(who) {
    var playerImage = Resource.get('player');
    var offset = Config.sprite.ratio * Config.sprite.positionOffsetValue;

    var positionOffset =
      who == 'A' ? {x: -offset, y: -offset} : {x: offset, y: offset};
    var player = this.createPlayer(who, playerImage, positionOffset);
    this.game.addSprite(player);
    this.players[who] = player;
  },

  executeNext: function(point) {
    var currentPlayer = Chess.currentPlayer;
    var currentPlayerName = currentPlayer.name;
    var nextPlayerName = currentPlayerName == 'A' ? 'B' : 'A';
    var nextPlayer = Chess.getPlayer(nextPlayerName);
    var pauseThrowNumber = nextPlayer.pauseThrowNumber;
    var msg1;
    var msg2;

    // Check surprise first, then check if the other player paused throw.
    if (point[2] !== undefined) {
      Chess.handleSurprise(point);
    } else if (pauseThrowNumber) {
      nextPlayer.pauseThrowNumber--;
      msg1 = Message.get('pauseThrowText', [nextPlayerName, pauseThrowNumber]);
      msg2 = Message.get('turnPlayer', currentPlayerName);
      Message.showMainInfo(msg1 + msg2, null, true);
      Socket.requestThrowDice(currentPlayerName);
      $.log('Player' + nextPlayerName + ' paused throw dice, Player ' +
        currentPlayerName + 'goes on.');
    } else {
      Chess.turnPlayer();
    }
  },

  turnPlayer: function() {
    var currentPlayerName = this.currentPlayer.name;
    var nextPlayerName = currentPlayerName == 'A' ? 'B' : 'A';
    this.currentPlayer = this.getPlayer(nextPlayerName);
    var message = Message.get('turnPlayer', nextPlayerName);
    Message.showMainInfo(message, null, true);
    Socket.requestThrowDice(nextPlayerName);
    $.log('Turn player to ' + nextPlayerName);
  },

  handleSurprise: function(point) {
    var player = Chess.currentPlayer;
    var playerName = player.name;
    var surprise = point[2];
    $.log('Surprise! ' + JSON.stringify(surprise));
    var msg;
    var audio;
    if (surprise) {
      switch (Object.keys(surprise)[0]) {
        case 'move':
          var move = surprise.move;
          if (move < 0) {
            msg = Message.get('backward', -move);
            audio = 'backward';
          } else {
            msg = Message.get('forward', move);
            audio = 'forward';
          }

          Message.showMainInfo(msg, function() {
            player.setPath(player.currentPointIndex,
              player.currentPointIndex + move, Chess.executeNext);
          });
          break;

        case 'rethrow':
          msg = Message.get('throwAgain');
          audio = 'rethrow';
          Message.showMainInfo(msg, function() {
            Socket.requestThrowDice(playerName);
          });
          break;

        case 'pauseThrow':
          var pauseNumber = surprise.pauseThrow;
          msg = Message.get('pauseThrow', pauseNumber);
          player.pauseThrowNumber = pauseNumber;
          audio = 'pauseThrow';
          Message.showMainInfo(msg, function() {
            Chess.turnPlayer();
          });
          break;

        case 'back_to_start':
          msg = Message.get('backToStart');
          audio = 'back-to-start';
          Message.showMainInfo(msg, function() {
            player.jump(0);
            Chess.turnPlayer();
          });
          break;

        case 'end':
          msg = Message.get('theWinner', playerName);
          audio = 'end';
          Message.showMainInfo(msg, function() {
            Chess.endGame(playerName);
          });
          break;
      }
      GameAudio.playSurpriseAudio(audio);
    }
  },

  removePlayer: function(name) {
    this.game.removeSprite(name);
    delete this.players[name];
    Message.showTip(Message.get('playerLeave', name));
  },
  
  clearPlayers: function() {
    for (var name in this.players)
      this.removePlayer(name);
  },

  endGame: function(playerName) {
    var that = this;
    Socket.endGame(playerName);
    this.ready = false;
    UI.showLastBattleResult(playerName);
    setTimeout(function() {
      that.clearPlayers();
      that.resetGame();
      Socket.registerView();
    }, 2000);
  },

  handleStopGame: function(name) {
    var message = Message.get('gameStop', name);
    Message.showTip(message);
    UI.hideLashBattleResult();
    this.clearPlayers();
    this.resetGame();
  }
};

Chess.init();